package org.wdcode.core.task;

import java.util.*;
import java.util.concurrent.locks.Lock;

import org.wdcode.common.log.WdLogs;
import org.wdcode.common.tools.Lists;
import org.wdcode.common.util.CommonUtil;
import org.wdcode.common.util.DateUtil;
import org.wdcode.core.concurrent.LockFactory;

/**
 * 任务发布引擎
 * @author WD
 * @since JDK6
 * @version 1.0 2010-07-12
 */
public class TaskEngine {
	// 高优先级
	public static final int			HIGH_PRIORITY	= 2;
	// 中优先级
	public static final int			MEDIUM_PRIORITY	= 1;
	// 低优先级
	public static final int			LOW_PRIORITY	= 0;
	// 锁
	private final static Lock		LOCK;
	// 队列
	private static PriorityQueue	taskQueue;
	// 组
	private static ThreadGroup		threadGroup;
	// 数组
	private static TaskEngineWorker	workers[];
	// 定时器
	private static Timer			taskTimer;
	// 新添加工作时间
	private static long				newWorkerTimestamp;
	// 删除工作时间
	private static long				busyTimestamp;
	// 是否开始标识
	private static boolean			started;

	/**
	 * 静态初始化
	 */
	static {
		// 锁
		LOCK = LockFactory.getLock();
		// 新添加工作时间
		newWorkerTimestamp = DateUtil.getTime();
		// 删除工作时间
		busyTimestamp = DateUtil.getTime();
		// 初始化
		initialize();
	}

	/**
	 * 优先级队列
	 * @author WD
	 * @since JDK6
	 * @version 1.0 2010-07-12
	 */
	private static class PriorityQueue {
		// 高优先级
		private LinkedList<Object>	high;
		// 中优先级
		private LinkedList<Object>	medium;
		// 低优先级
		private LinkedList<Object>	low;

		/**
		 * 私有构造
		 */
		private PriorityQueue() {
			// 高优先级
			high = Lists.getLinkedList();
			// 中优先级
			medium = Lists.getLinkedList();
			// 低优先级
			low = Lists.getLinkedList();
		}

		/**
		 * 插入队列
		 * @param priority 优先级
		 * @param object 对象
		 */
		public void enqueue(int priority, Object object) {
			// 判断优先级是否在范围内
			if (priority > HIGH_PRIORITY) {
				priority = HIGH_PRIORITY;
			} else if (priority < LOW_PRIORITY) {
				priority = LOW_PRIORITY;
			}
			// 根据优先级 放入队列
			switch (priority) {
				case HIGH_PRIORITY:
					// 高优先级
					high.addFirst(object);
					break;
				case MEDIUM_PRIORITY:
					// 中优先级
					medium.addFirst(object);
					break;
				case LOW_PRIORITY:
					// 低优先级
					low.addFirst(object);
					break;
			}
		}

		/**
		 * 判断队列是否为空
		 * @return 是否空
		 */
		public boolean isEmpty() {
			return high.isEmpty() && medium.isEmpty() && low.isEmpty();
		}

		/**
		 * 队列数量
		 * @return 数量
		 */
		public int size() {
			return high.size() + medium.size() + low.size();
		}

		/**
		 * 删除最后的任务对象
		 * @return 任务对象
		 */
		public Object dequeue() {
			// 任务对象
			Object object = null;
			// 删除任务对象
			if (!CommonUtil.isEmpty(high)) {
				object = high.removeLast();
			} else if (!CommonUtil.isEmpty(medium)) {
				object = medium.removeLast();
			} else if (!CommonUtil.isEmpty(low)) {
				object = low.removeLast();
			}
			// 交换任务对象
			if (!CommonUtil.isEmpty(low)) {
				medium.addFirst(low.removeLast());
			}
			// 交换任务对象
			if (!CommonUtil.isEmpty(medium)) {
				high.addFirst(medium.removeLast());
			}
			// 返回任务对象
			return object;
		}
	}

	/**
	 * 内部类 添加任务
	 * @author WD
	 * @since JDK6
	 * @version 1.0 2010-07-12
	 */
	private static class ScheduledTask extends TimerTask {
		// 优先级
		private int			priority;
		// 任务
		private Runnable	task;

		/**
		 * 线程运行
		 */
		public void run() {
			TaskEngine.addTask(priority, task);
		}

		/**
		 * 构造函数
		 * @param priority 优先级
		 * @param task 任务
		 */
		ScheduledTask(int priority, Runnable task) {
			this.priority = priority;
			this.task = task;
		}
	}

	/**
	 * 任务工作类
	 * @author WD
	 * @since JDK6
	 * @version 1.0 2010-07-12
	 */
	private static class TaskEngineWorker extends Thread {
		// 工作标识
		private boolean	done;

		/**
		 * 构造方法
		 * @param name 名称
		 */
		TaskEngineWorker(String name) {
			super(TaskEngine.threadGroup, name);
			done = false;
		}

		/**
		 * 停止工作
		 */
		public void stopWorker() {
			done = true;
		}

		/**
		 * 运行线程
		 */
		public void run() {
			// 循环
			do {
				// 如果停止任务就跳出循环
				if (done) {
					break;
				}
				// 获得优先级
				int currentThreadPriority = getPriority();
				// 新线程优先级
				int newThreadPriority = currentThreadPriority;
				try {
					// 获得下一个工作任务
					TaskWrapper wrapper = TaskEngine.nextTask();
					// 获得任务优先级
					int desiredTaskPriority = wrapper.getPriority();
					// 配置新优先级
					newThreadPriority = desiredTaskPriority != 2 ? ((int) (desiredTaskPriority != 1 ? 2 : 5)) : 9;
					// 设置优先级
					setPriority(newThreadPriority, currentThreadPriority);
					// 运行任务
					wrapper.getTask().run();
					// 设置优先级
					setPriority(newThreadPriority, currentThreadPriority);
				} catch (Exception e) {
					WdLogs.error(e);
					// 设置优先级
					setPriority(newThreadPriority, currentThreadPriority);
				}
			} while (true);
		}

		/**
		 * 设置优先级
		 * @param newThreadPriority 新优先级
		 * @param currentThreadPriority 当前优先级
		 */
		private void setPriority(int newThreadPriority, int currentThreadPriority) {
			// 新优先级不等于现在的优先级
			if (newThreadPriority != currentThreadPriority) {
				try {
					// 设置优先级
					setPriority(currentThreadPriority);
				} catch (Exception e) {
					WdLogs.error(e);
				}
			}
		}
	}

	/**
	 * 私有构造
	 */
	private TaskEngine() {}

	/**
	 * 开始执行
	 */
	public static void start() {
		LOCK.lock();
		started = true;
		LOCK.unlock();
	}

	/**
	 * 获得大小
	 * @return 大小
	 */
	public final static int size() {
		LOCK.lock();
		int size = taskQueue.size();
		LOCK.unlock();
		return size;
	}

	/**
	 * 获得任务数量
	 * @return 数量
	 */
	public final static int getNumWorkers() {
		return workers.length;
	}

	/**
	 * 添加任务
	 * @param task 任务
	 */
	public final static void addTask(Runnable task) {
		addTask(1, task);
	}

	/**
	 * 添加任务
	 * @param priority 优先级
	 * @param task 任务
	 */
	public final static void addTask(int priority, Runnable task) {
		// 锁
		LOCK.lock();
		// 判断相关条件
		if ((double) taskQueue.size() > Math.ceil(workers.length / 2)) {
			// 获得时间
			busyTimestamp = DateUtil.getTime();
			// 添加工作
			addWorker();
		} else if (workers.length > 3) {
			// 删除工作
			removeWorker();
		}
		// 声明工作任务
		TaskWrapper wrapper = new TaskWrapper(priority, task);
		// 插入队列
		taskQueue.enqueue(priority, wrapper);
		// 解锁
		LOCK.unlock();
	}

	/**
	 * 安排任务
	 * @param task 任务
	 * @param date 时间
	 * @return 定时任务
	 */
	public final static TimerTask scheduleTask(Runnable task, Date date) {
		return scheduleTask(1, task, date);
	}

	/**
	 * 安排任务
	 * @param priority 优先级
	 * @param task 任务
	 * @param date 时间
	 * @return 定时任务
	 */
	public final static TimerTask scheduleTask(int priority, Runnable task, Date date) {
		// 生成定时服务
		TimerTask timerTask = new ScheduledTask(priority, task);
		// 安排任务
		taskTimer.schedule(timerTask, date);
		// 返回定时服务
		return timerTask;
	}

	/**
	 * 安排任务
	 * @param task 任务
	 * @param delay 启动时间
	 * @param period 延迟时间
	 * @return 定时任务
	 */
	public final static TimerTask scheduleTask(Runnable task, long delay, long period) {
		return scheduleTask(1, task, delay, period);
	}

	/**
	 * 安排任务
	 * @param priority 优先级
	 * @param task 任务
	 * @param delay 启动时间
	 * @param period 延迟时间
	 * @return 定时任务
	 */
	public final static TimerTask scheduleTask(int priority, Runnable task, long delay, long period) {
		// 生成定时服务
		TimerTask timerTask = new ScheduledTask(priority, task);
		// 安排任务
		taskTimer.scheduleAtFixedRate(timerTask, delay, period);
		// 返回定时服务
		return timerTask;
	}

	/**
	 * 停止任务
	 */
	public final static void shutdown() {
		taskTimer.cancel();
	}

	/**
	 * 重启任务
	 */
	public final static void restart() {
		shutdown();
		initialize();
	}

	/**
	 * 返回下个任务
	 * @return 工作任务
	 */
	private static TaskWrapper nextTask() {
		// 锁
		LOCK.lock();
		// 队列不为空
		while (taskQueue.isEmpty() || !started) {
			try {
				LOCK.wait();
			} catch (InterruptedException ie) {}
		}
		// 解锁
		LOCK.unlock();
		// 在队列中返回工作任务
		return (TaskWrapper) taskQueue.dequeue();

	}

	/**
	 * 添加工作任务
	 */
	private static void addWorker() {
		// 符合一定条件才能添加
		if (workers.length < 30 && System.currentTimeMillis() > newWorkerTimestamp + 2000L) {
			// 工作任务加1
			int newSize = workers.length + 1;
			// 最后任务数组标识
			int lastIndex = newSize - 1;
			// 新建工作任务数组
			TaskEngineWorker newWorkers[] = new TaskEngineWorker[newSize];
			// 拷贝老数组
			System.arraycopy(workers, 0, newWorkers, 0, workers.length);
			// 设置新任务启动
			newWorkers[lastIndex] = new TaskEngineWorker("Task Engine Worker " + lastIndex);
			newWorkers[lastIndex].setDaemon(true);
			newWorkers[lastIndex].start();
			// 替换原任务数组
			workers = newWorkers;
			// 添加新任务时间
			newWorkerTimestamp = System.currentTimeMillis();
		}
	}

	/**
	 * 删除工作任务
	 */
	private static void removeWorker() {
		// 符合一定条件才能删除
		if (workers.length > 3 && System.currentTimeMillis() > busyTimestamp + 5000L) {
			// 停止任务
			workers[workers.length - 1].stopWorker();
			// 新的大小
			int newSize = workers.length - 1;
			// 声明数组
			TaskEngineWorker newWorkers[] = new TaskEngineWorker[newSize];
			// 拷贝数组
			System.arraycopy(workers, 0, newWorkers, 0, newSize);
			// 替换原任务数组
			workers = newWorkers;
			// 删除新任务时间
			busyTimestamp = System.currentTimeMillis();
		}
	}

	/**
	 * 初始化
	 */
	private static void initialize() {
		// 初始化定时服务
		taskTimer = new Timer(true);
		// 初始化任务队列
		taskQueue = new PriorityQueue();
		// 初始化任务组
		threadGroup = new ThreadGroup("Task Engine Workers");
		// 初始化任务数组
		workers = new TaskEngineWorker[5];
		// 添加数组
		for (int i = 0; i < workers.length; i++) {
			workers[i] = new TaskEngineWorker("Task Engine Worker " + i);
			workers[i].setDaemon(true);
			workers[i].start();
		}
	}
}